package cn.wolfcode.car.business.service.impl;

import cn.wolfcode.car.business.domain.BpmnInfo;
import cn.wolfcode.car.business.domain.Contract;
import cn.wolfcode.car.business.domain.ContractAudit;
import cn.wolfcode.car.business.domain.Statement;
import cn.wolfcode.car.business.mapper.BpmnInfoMapper;
import cn.wolfcode.car.business.mapper.ContractAuditMapper;
import cn.wolfcode.car.business.mapper.ContractMapper;
import cn.wolfcode.car.business.mapper.StatementMapper;
import cn.wolfcode.car.business.query.ContractQuery;
import cn.wolfcode.car.business.service.IContractService;
import cn.wolfcode.car.common.base.page.TablePageInfo;
import cn.wolfcode.car.common.config.SystemConfig;
import cn.wolfcode.car.common.exception.BusinessException;
import cn.wolfcode.car.common.util.Convert;
import cn.wolfcode.car.common.util.file.FileUploadUtils;
import cn.wolfcode.car.common.util.uuid.UUID;
import cn.wolfcode.car.shiro.ShiroUtils;
import com.github.pagehelper.PageHelper;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Transactional
public class ContractServiceImpl implements IContractService {

    @Autowired
    private ContractMapper contractMapper;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private BpmnInfoMapper bpmnInfoMapper;
    @Autowired
    private ContractAuditMapper contractAuditMapper;
    @Autowired
    private TaskService taskService;


    @Override
    public TablePageInfo<Contract> query(ContractQuery qo) {
        PageHelper.startPage(qo.getPageNum(), qo.getPageSize());
        return new TablePageInfo<Contract>(contractMapper.selectForList(qo));
    }


    @Override
    public void save(Contract contract,Long bpmnInfoId,Long director) {
        // 设置默认值、未输入值
        contract.setAffixSealState(Contract.CON_AFFIX_SEAL_STATE_NO);
        contract.setAuditState(Contract.CON_AUDIT_STATE_UNAPPROVED);
        contract.setNullifyState(Contract.CON_NULLIFY_STATE_ON);
        contract.setInputUser(ShiroUtils.getUserId());
        contract.setInputTime(new Date());

        // 新增操作
        contractMapper.insert(contract);


        // bus_contract_audit表新增数据
        ContractAudit contractAudit = new ContractAudit();
        contractAudit.setContractId(contract.getId());
        contractAudit.setCreator(ShiroUtils.getUser().getUserName());
        contractAudit.setAuditorId(director);
        contractAudit.setBpmninfoId(bpmnInfoId.intValue());
        contractAudit.setInfo(null);
        contractAudit.setAuditTime(null);
        contractAudit.setCreateTime(new Date());
        contractAuditMapper.insert(contractAudit);

        // 发起审核
        BpmnInfo bpmnInfo = bpmnInfoMapper.selectByPrimaryKey(bpmnInfoId);
        Map<String,Object> map = new HashMap<>();
        map.put("director",director);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(bpmnInfo.getActProcessKey(), contractAudit.getId().toString(), map);

        contractAuditMapper.changeInstanceId(contractAudit.getId(),processInstance.getProcessInstanceId());
    }

    @Override
    public Contract get(Long id) {
        return contractMapper.selectByPrimaryKey(id);
    }


    @Override
    public void update(Contract contract) {
        Contract dbItem = this.get(contract.getId());
        // 非在用状态/已盖章状态/非未审核状态 报错
        if (Contract.CON_NULLIFY_STATE_OFF.equals(dbItem.getNullifyState()) || Contract.CON_AFFIX_SEAL_STATE_YES.equals(dbItem.getAffixSealState()) || !Contract.CON_AUDIT_STATE_UNAPPROVED.equals(dbItem.getAuditState())) {
            throw new BusinessException("非法操作");
        }

        // 录入人、录入时间、作废状态、盖章状态、审核状态 不用修改 改sql语句

        // 未知需求：编辑前的合同附件不知道要不要删掉

        // 修改操作
        contractMapper.updateByPrimaryKey(contract);
    }

    @Override
    public void deleteBatch(String ids) {
        Long[] dictIds = Convert.toLongArray(ids);
        for (Long dictId : dictIds) {
            contractMapper.deleteByPrimaryKey(dictId);
        }
    }

    @Override
    public List<Contract> list() {
        return contractMapper.selectAll();
    }

    @Override
    public String uploadFile(MultipartFile file) throws IOException {
        // 空文件报错
        if (file == null) {
            throw new BusinessException("请上传合同电子附件！");
        }

        // 非pdf文件报错
        String extension = FileUploadUtils.getExtension(file);
        if (!"pdf".equals(extension)) {
            throw new BusinessException("请上传PDF格式文件");
        }

        // 上传文件
        String path = FileUploadUtils.upload(SystemConfig.getProfile(), file);
        return path;
    }

    @Override
    public String downloadContract(Long id, HttpServletRequest request) throws IOException {
        return SystemConfig.getProfile();
    }

    @Override
    public void useless(Long id) {
        Contract contract = this.get(id);
        // 非在用状态作废 报错
        if (Contract.CON_NULLIFY_STATE_OFF.equals(contract.getNullifyState())) {
            throw new BusinessException("非法操作");
        }

        // 如果该合同在未审核状态，则有进行中的审核流程，关闭流程实例
        if (Contract.CON_AUDIT_STATE_UNAPPROVED.equals(contract.getAuditState())) {
            ContractAudit contractAudit = contractAuditMapper.selectByContractId(id);
            runtimeService.deleteProcessInstance(contractAudit.getInstanceId().toString(),"作废");
        }

        // 修改作废状态
        contractMapper.changeNullifyState(id,Contract.CON_NULLIFY_STATE_OFF);
    }

    @Override
    public void approve(Long id) {
        Contract contract = this.get(id);
        // 作废状态、非未审核状态、已盖章状态下 审核通过则报错
        if (Contract.CON_NULLIFY_STATE_OFF.equals(contract.getNullifyState()) || !Contract.CON_AUDIT_STATE_UNAPPROVED.equals(contract.getAuditState()) || Contract.CON_AFFIX_SEAL_STATE_YES.equals(contract.getAffixSealState())) {
            throw new BusinessException("非法操作");
        }

        ContractAudit contractAudit = contractAuditMapper.selectByContractId(id);

        // 审核人非 杨龙 则报错
        if (!ShiroUtils.getUserId().equals(contractAudit.getAuditorId())) {
            throw new BusinessException("杨龙才有权限审核！");
        }

        // 完成审核节点流程
        Task task = taskService.createTaskQuery().processInstanceId(contractAudit.getInstanceId().toString()).singleResult();
        taskService.complete(task.getId());

        // 修改bus_contract_audit表 status、auditTime
        contractAuditMapper.changeStatus(contractAudit.getId(),ContractAudit.CON_AUDIT_STATE_APPROVED);
        contractAuditMapper.changeAuditTime(contractAudit.getId(),new Date());

        // 修改bus_contract表 auditState
        contractMapper.changeAuditState(id,Contract.CON_AUDIT_STATE_APPROVED);
    }

    @Override
    public void unapprove(Long id) {
        Contract contract = this.get(id);
        // 作废状态、非未审核状态、已盖章状态下 审核通过则报错
        if (Contract.CON_NULLIFY_STATE_OFF.equals(contract.getNullifyState()) || !Contract.CON_AUDIT_STATE_UNAPPROVED.equals(contract.getAuditState()) || Contract.CON_AFFIX_SEAL_STATE_YES.equals(contract.getAffixSealState())) {
            throw new BusinessException("非法操作");
        }

        ContractAudit contractAudit = contractAuditMapper.selectByContractId(id);

        // 审核人非 杨龙 则报错
        if (!ShiroUtils.getUserId().equals(contractAudit.getAuditorId())) {
            throw new BusinessException("杨龙才有权限审核！");
        }

        // 完成审核节点流程
        Task task = taskService.createTaskQuery().processInstanceId(contractAudit.getInstanceId().toString()).singleResult();
        taskService.complete(task.getId());

        // 修改bus_contract_audit表 status、auditTime
        contractAuditMapper.changeStatus(contractAudit.getId(),ContractAudit.CON_AUDIT_STATE_REJECT);
        contractAuditMapper.changeAuditTime(contractAudit.getId(),new Date());

        // 修改bus_contract表 auditState
        contractMapper.changeAuditState(id,Contract.CON_AUDIT_STATE_REJECT);
    }

    @Override
    public void affixSeal(Long id) {
        Contract contract = this.get(id);
        // 作废状态、非审核通过状态、已盖章状态下 审核通过则报错
        if (Contract.CON_NULLIFY_STATE_OFF.equals(contract.getNullifyState()) || !Contract.CON_AUDIT_STATE_APPROVED.equals(contract.getAuditState()) || Contract.CON_AFFIX_SEAL_STATE_YES.equals(contract.getAffixSealState())) {
            throw new BusinessException("非法操作");
        }

        // 修改盖章状态
        contractMapper.changeAffixSealState(id,Contract.CON_AFFIX_SEAL_STATE_YES);
    }

    @Override
    public String uploadFileMinio(MultipartFile file) throws Exception {
        // 空文件报错
        if (file == null) {
            throw new BusinessException("请上传合同电子附件！");
        }

        // 非PDF文件报错
        String extension = FileUploadUtils.getExtension(file);
        if (!"pdf".equals(extension)) {
            throw new BusinessException("请上传PDF格式文件！");
        }
        return FileUploadUtils.minIoUpload(file);
    }

    @Override
    public String uploadFile2(MultipartFile file) throws IOException {
        // 空文件报错
        if (file == null) {
            throw new BusinessException("请上传合同电子附件！");
        }

        // 非PDF文件报错
        String extension = FileUploadUtils.getExtension(file);
        if (!"pdf".equals(extension)) {
            throw new BusinessException("请上传PDF格式文件！");
        }

        InputStream inputStream = file.getInputStream();

        String uuid = UUID.randomUUID().toString();
        String path = "/goodsCover/" + uuid + "." + extension;
        Path path1 = Paths.get("src/main/resources/static", path);
        Files.copy(inputStream,path1);
        inputStream.close();
        return path;
    }

    @Override
    public void downloadContract2(Long id, HttpServletResponse response) throws IOException {
        Contract contract = contractMapper.selectByPrimaryKey(id);
        // 获取合同文件名
        String fileName = contract.getAppendix();


        response.setHeader("Content-Disposition","attachment;filename=1111.pdf");
        response.setContentType("application/octet-stream");

        File file = new File("src/main/resources/static",fileName);
        FileInputStream in = new FileInputStream(file);

        ServletOutputStream outputStream = response.getOutputStream();

        byte[] b = new byte[1024];
        int len = 0;
        while((len = in.read(b)) != -1) {
            outputStream.write(b,0,len);
        }

        outputStream.close();
        in.close();
    }
}
